{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 准备数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import tensorflow as tf\n",
    "from tensorflow import keras\n",
    "from tensorflow.keras import layers, optimizers, datasets\n",
    "from tensorflow.keras.layers import Dense, Dropout, Flatten\n",
    "from tensorflow.keras.layers import Conv2D, MaxPooling2D\n",
    "\n",
    "os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'  # or any {'0', '1', '2'}\n",
    "\n",
    "def mnist_dataset():\n",
    "    (x, y), (x_test, y_test) = datasets.mnist.load_data()\n",
    "    x = x.reshape(x.shape[0], 28, 28,1)\n",
    "    x_test = x_test.reshape(x_test.shape[0], 28, 28,1)\n",
    "    ds = tf.data.Dataset.from_tensor_slices((x, y))\n",
    "    ds = ds.map(prepare_mnist_features_and_labels)\n",
    "    ds = ds.take(20000).batch(100)\n",
    "    \n",
    "    test_ds = tf.data.Dataset.from_tensor_slices((x_test, y_test))\n",
    "    test_ds = test_ds.map(prepare_mnist_features_and_labels)\n",
    "    test_ds = test_ds.take(20000).batch(20000)\n",
    "    return ds, test_ds\n",
    "\n",
    "def prepare_mnist_features_and_labels(x, y):\n",
    "    x = tf.cast(x, tf.float32) / 255.0\n",
    "    y = tf.cast(y, tf.int64)\n",
    "    return x, y"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 建立模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class myConvModel(keras.Model):\n",
    "    def __init__(self):\n",
    "        super(myConvModel, self).__init__()\n",
    "        self.l1_conv = Conv2D(filters=32, \n",
    "                              kernel_size=(5, 5), \n",
    "                              activation='relu', padding='same')\n",
    "        \n",
    "        self.l2_conv = Conv2D(filters=64, \n",
    "                              kernel_size=(5, 5), \n",
    "                              activation='relu',padding='same')\n",
    "        \n",
    "        self.pool = MaxPooling2D(pool_size=(2, 2), strides=2)\n",
    "        \n",
    "        self.flat = Flatten()\n",
    "        self.dense1 = layers.Dense(100, activation='tanh')\n",
    "        self.dense2 = layers.Dense(10)\n",
    "    @tf.function\n",
    "    def call(self, x):\n",
    "        '''shape(x) = [32, 28, 28, 1]'''\n",
    "        h1 = self.l1_conv(x) # [32, 28, 28, 32]\n",
    "        h1_pool = self.pool(h1) # [32, 14, 14, 32]\n",
    "        h2 = self.l2_conv(h1_pool) #[32, 14, 14, 64]\n",
    "        '''kernel 参数量64*5*5*32'''\n",
    "        h2_pool = self.pool(h2) #[32, 7, 7, 64]\n",
    "        flat_h = self.flat(h2_pool) #[32, 7*7*64]\n",
    "        dense1 = self.dense1(flat_h) #[32, 100]\n",
    "        logits = self.dense2(dense1) #[32, 10]\n",
    "        probs = tf.nn.softmax(logits, axis=-1) #[32, 10]\n",
    "        return probs\n",
    "\n",
    "model = myConvModel()\n",
    "optimizer = optimizers.Adam()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 编译， fit以及evaluate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "W0907 16:16:17.882842 4609922496 training_utils.py:1436] Expected a shuffled dataset but input dataset `x` is not shuffled. Please invoke `shuffle()` on input dataset.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/5\n",
      "200/200 [==============================] - 30s 149ms/step - loss: 0.3044 - accuracy: 0.8122\n",
      "Epoch 2/5\n",
      "200/200 [==============================] - 29s 147ms/step - loss: 0.0852 - accuracy: 0.9713\n",
      "Epoch 3/5\n",
      "200/200 [==============================] - 29s 144ms/step - loss: 0.0504 - accuracy: 0.9838\n",
      "Epoch 4/5\n",
      "200/200 [==============================] - 27s 135ms/step - loss: 0.0301 - accuracy: 0.9901\n",
      "Epoch 5/5\n",
      "200/200 [==============================] - 27s 135ms/step - loss: 0.0194 - accuracy: 0.9946\n",
      "1/1 [==============================] - 6s 6s/step - loss: 0.0502 - accuracy: 0.9834\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[0.050157830119132996, 0.9834]"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.compile(optimizer=optimizer,\n",
    "              loss='sparse_categorical_crossentropy',\n",
    "              metrics=['accuracy'])\n",
    "train_ds, test_ds = mnist_dataset()\n",
    "model.fit(train_ds, epochs=5)\n",
    "model.evaluate(test_ds)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f(1) == 1\n",
    "f(2) == 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f(2) == 5\n",
    "f(1) == 2"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
